#include "container/stack.h"
#include <stdio.h>

#include "unity.h"

void test_StackInit(void)
{
    uint8_t buf[10];
    cotStack_t stack;

    cotStack_Init(&stack, buf, sizeof(buf), sizeof(int));
    TEST_ASSERT_EQUAL_PTR(buf, stack.pBuf);
    TEST_ASSERT_EQUAL_UINT(sizeof(int), stack.itemSize);
    TEST_ASSERT_EQUAL_UINT(sizeof(buf) / sizeof(int), stack.limit);
    TEST_ASSERT_EQUAL_UINT(0, stack.idx);
}

void test_StackEmpty(void)
{
    uint8_t buf[10];
    cotStack_t stack;

    cotStack_Init(&stack, buf, sizeof(buf), sizeof(int));
    TEST_ASSERT_TRUE(cotStack_Empty(&stack));

    int data = 42;
    cotStack_Push(&stack, &data, sizeof(data));
    TEST_ASSERT_FALSE(cotStack_Empty(&stack));
}

void test_StackFull(void)
{
    uint8_t buf[10];
    cotStack_t stack;

    cotStack_Init(&stack, buf, sizeof(buf), sizeof(int));
    TEST_ASSERT_FALSE(cotStack_Full(&stack));

    int data = 42;

    for (int i = 0; i < sizeof(buf) / sizeof(int); i++)
    {
        cotStack_Push(&stack, &data, sizeof(data));
    }

    TEST_ASSERT_TRUE(cotStack_Full(&stack));
}

void test_StackSize(void)
{
    uint8_t buf[10];
    cotStack_t stack;

    cotStack_Init(&stack, buf, sizeof(buf), sizeof(int));
    TEST_ASSERT_EQUAL_UINT(0, cotStack_Size(&stack));

    int data = 42;
    cotStack_Push(&stack, &data, sizeof(data));
    TEST_ASSERT_EQUAL_UINT(1, cotStack_Size(&stack));
}

void test_StackTop(void)
{
    uint8_t buf[20];
    cotStack_t stack;

    cotStack_Init(&stack, buf, sizeof(buf), sizeof(int));

    int data1 = 42, data2 = 425, data3 = 748;
    cotStack_Push(&stack, &data1, sizeof(data1));
    cotStack_Push(&stack, &data2, sizeof(data2));
    cotStack_Push(&stack, &data3, sizeof(data3));
    int *pData = (int *)cotStack_Top(&stack);
    TEST_ASSERT_EQUAL_INT(data3, *pData);
}

void test_StackPush(void)
{
    uint8_t buf[10];
    cotStack_t stack;

    cotStack_Init(&stack, buf, sizeof(buf), sizeof(int));

    int data = 42;
    int ret = cotStack_Push(&stack, &data, sizeof(data));
    TEST_ASSERT_EQUAL_INT(0, ret);
    TEST_ASSERT_EQUAL_UINT(1, cotStack_Size(&stack));
}

void test_StackPop(void)
{
    uint8_t buf[10];
    cotStack_t stack;

    cotStack_Init(&stack, buf, sizeof(buf), sizeof(int));
    int data = 42;
    cotStack_Push(&stack, &data, sizeof(data));

    cotStack_Pop(&stack);
    TEST_ASSERT_TRUE(cotStack_Empty(&stack));
}

void test_StackSwap(void)
{
    uint8_t buf1[10];
    uint8_t buf2[10];
    cotStack_t stack1, stack2;

    cotStack_Init(&stack1, buf1, sizeof(buf1), sizeof(int));
    cotStack_Init(&stack2, buf2, sizeof(buf2), sizeof(int));

    int data1 = 1, data2 = 2;

    cotStack_Push(&stack1, &data1, sizeof(data1));
    cotStack_Push(&stack1, &data2, sizeof(data2));

    cotStack_Swap(&stack1, &stack2);

    int *pData = (int *)cotStack_Top(&stack2);
    TEST_ASSERT_EQUAL_INT(data2, *pData);
    cotStack_Pop(&stack2);

    pData = (int *)cotStack_Top(&stack2);
    TEST_ASSERT_EQUAL_INT(data1, *pData);
    cotStack_Pop(&stack2);

    TEST_ASSERT_TRUE(cotStack_Empty(&stack2));
}

void test_StackSwapEmpty(void)
{
    uint8_t buf1[10];
    uint8_t buf2[10];
    cotStack_t stack1, stack2;

    cotStack_Init(&stack1, buf1, sizeof(buf1), sizeof(int));
    cotStack_Init(&stack2, buf2, sizeof(buf2), sizeof(int));

    cotStack_Swap(&stack1, &stack2);

    TEST_ASSERT_TRUE(cotStack_Empty(&stack1));
    TEST_ASSERT_TRUE(cotStack_Empty(&stack2));
}

void test_StackSwapNonEmptyAndEmpty(void)
{
    uint8_t buf1[10];
    uint8_t buf2[10];
    cotStack_t stack1, stack2;

    cotStack_Init(&stack1, buf1, sizeof(buf1), sizeof(int));
    cotStack_Init(&stack2, buf2, sizeof(buf2), sizeof(int));

    int data1 = 1, data2 = 2;

    cotStack_Push(&stack1, &data1, sizeof(data1));
    cotStack_Push(&stack1, &data2, sizeof(data2));

    cotStack_Swap(&stack1, &stack2);

    TEST_ASSERT_TRUE(cotStack_Empty(&stack1));
    TEST_ASSERT_FALSE(cotStack_Empty(&stack2));

    int *pData = (int *)cotStack_Top(&stack2);
    TEST_ASSERT_EQUAL_INT(data2, *pData);
    
    TEST_ASSERT_EQUAL_UINT(0, cotStack_Size(&stack1));
    TEST_ASSERT_EQUAL_UINT(2, cotStack_Size(&stack2));
}


int test_Stack(void)
{
    UNITY_BEGIN();  // 初始化 Unity 测试框架

    RUN_TEST(test_StackInit);
    RUN_TEST(test_StackEmpty);
    RUN_TEST(test_StackFull);
    RUN_TEST(test_StackSize);
    RUN_TEST(test_StackTop);
    RUN_TEST(test_StackPush);
    RUN_TEST(test_StackPop);
    RUN_TEST(test_StackSwap);

    RUN_TEST(test_StackSwapEmpty);
    RUN_TEST(test_StackSwapNonEmptyAndEmpty);
    

    UNITY_END();  // 结束测试

    return 0;
}